﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using System.IO;
using TSL_Tools.SqlTools;

namespace ReportingEngine
{
    public partial class TSL_ReportingEngine
    {
        #region properties
        /// <summary>
        /// The SQL connection string used to connect to the LoadTest2010 datbase
        /// </summary>
        public string sqlConn { get; set; }        

        /// <summary>
        /// The timeout for connecting to the LoadTest2010 database
        /// </summary>
        public int connTimeout { get; set; }

        /// <summary>
        /// The timeout period for SQL commands to execute
        /// </summary>
        public int cmdTimeout { get; set; }

        /// <summary>
        /// The minimum number of samples that need to be at the same value in order to consider a run's interval to be at a constant load
        /// </summary>
        public int minimumPointsForConstantInterval { get; set; }

        /// <summary>
        /// The minimum number of seconds that need to be at the same value in order to consider a run's interval to be at a constant load
        /// </summary>
        public int minimumSecondsForConstantInterval { get; set; }

        /// <summary>
        /// Flag that denotes whether the UserName that gets added to the analysis notes (the 'Comments' column in the LoadTestRun table) should be ignored when processing results.
        /// </summary>
        public bool IgnoreUserNameFromAnalysisNotes { get; set; }

        /// <summary>
        /// The folder that contains the SQL Scripts to execute when updating the LoadTestDatabase.
        /// </summary>
        public string SqlScriptLocation { get; set; }

        /// <summary>
        /// The name of the load test datatbase. The default value  is 'LoadTest2010'.
        /// </summary>
        public string LoadTestDatabaseName { get; set; }

        /// <summary>
        /// Collection of all the the runs, including core info
        /// </summary>
        public Dictionary<int, LoadTestCoreInfo> listOfRuns { get; set; }

        /// <summary>
        /// A list of items that the user configured for how to build scorecard reports
        /// </summary>
        public List<ScoreCardItem> ScoreCardItems { get; set; }

        /// <summary>
        /// XML Doc that contains the structure of the Load Test as stored in the results DB
        /// </summary>
        public XmlDocument xDoc { get; set; }

        public string mostRecentSqlQuery { get; set; }

        private TalkToSql tts;
        #endregion

        #region constructors
        public TSL_ReportingEngine(string sqlConnection)
        {
            MyInitialization(sqlConnection, 60, 300);
        }

        public TSL_ReportingEngine(string sqlConnection, int connectionTimeout)
        {
            MyInitialization(sqlConnection, connectionTimeout, 300);
        }

        public TSL_ReportingEngine(string sqlConnection, int connectionTimeout, int commandTimeout)
        {
            MyInitialization(sqlConnection, connectionTimeout, commandTimeout);
        }

        private void SetDefaultConfigValues()
        {
            minimumPointsForConstantInterval = 10;
            minimumSecondsForConstantInterval = 60;
            IgnoreUserNameFromAnalysisNotes = true;
            SqlScriptLocation = "\\SqlScripts\\";
            LoadTestDatabaseName = "LoadTest2010";
        }

        // Routines that have to run for all of the constructors
        private void MyInitialization(string sqlConnection, int connectionTimeout, int commandTimeout)
        {
            sqlConn = sqlConnection;
            connTimeout = connectionTimeout;
            cmdTimeout = commandTimeout;

            tts = new TalkToSql(sqlConn, connTimeout, cmdTimeout);

            listOfRuns = new Dictionary<int, LoadTestCoreInfo>();
            xDoc = new XmlDocument();
            ScoreCardItems = new List<ScoreCardItem>();
            GetExtendedSettings();
            SetDefaultConfigValues();
        }
        #endregion
    }


    public class LoadTestCoreInfo
    {
        /// <summary>
        /// The run Id for the run stored in this instance of the class
        /// </summary>
        public int runId { get; set; }

        public string LoadTestName { get; set; }
        public string description { get; set; }
        public string analysisNotes { get; set; }

        public DateTime startTime { get; set; }
        public int duration { get; set; }
        public int sampleRate { get; set; }
        public string outcome { get; set; }

        public string runSettingsUsed { get; set; }
        public string controllerName { get; set; }
        public ResultTypesStoredInLoadTest resultTypes { get; set; }

        // Scorecard items
        public DataTable scorecardItems { get; set; }

        public string loadTestRunXmlAsString { get; set; }
        
        /// <summary>
        /// This dictionary contains all of the run settings for the given load test run.
        /// </summary>
        public Dictionary<string, string> runConfiguration { get; set; }

        /// <summary>
        /// This dictionary contains a list of all of the scenarios in the load test
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> scenarios { get; set; }

        /// <summary>
        /// List of all of the agent machines for the run
        /// </summary>
        public Collection<string> agents { get; set; }

        /// <summary>
        /// List of all machines that have a counterset mapping in the load test
        /// </summary>
        public Collection<string> sutMachines { get; set; }

        /// <summary>
        /// List of all machines that have at least one entry in the Perfmon counter collection
        /// </summary>
        public Collection<string> perfmonMachines { get; set; }

        public LoadTestCoreInfo()
        {
            runConfiguration = new Dictionary<string, string>();
            scenarios = new Dictionary<string, Dictionary<string, string>>();
            agents = new Collection<string>();
            sutMachines = new Collection<string>();
            perfmonMachines = new Collection<string>();
            scorecardItems = new DataTable();
        }
        #region -- methods --------------------------------------
        public LoadTestCoreInfo Clone()
        {
            LoadTestCoreInfo clones = new LoadTestCoreInfo();

            clones.runId = runId;
            clones.LoadTestName = LoadTestName;
            clones.description = description;
            clones.analysisNotes = analysisNotes;
            clones.startTime = startTime;
            clones.duration = duration;
            clones.sampleRate = sampleRate;
            clones.runSettingsUsed = runSettingsUsed;
            clones.controllerName = controllerName;
            clones.resultTypes = resultTypes;
            clones.runConfiguration = runConfiguration;
            clones.scenarios = scenarios;
            clones.sutMachines = sutMachines;
            clones.perfmonMachines = perfmonMachines;
            clones.agents = agents;
            clones.loadTestRunXmlAsString = loadTestRunXmlAsString;
            clones.outcome = outcome;
            clones.scorecardItems = scorecardItems;

            return clones;
        }

        public TimeSpan GetScorecardTable(string sqlConn, int connTimeout, int cmdTimeout)
        {
            TalkToSql tts = new TalkToSql(sqlConn, connTimeout, cmdTimeout);
            string sqlCmd = String.Format(TSL_ReportingEngine.Sql_GETCORESCORECARDVALUESFORSINGLERUN, runId);
            DataTable _table;
            TimeSpan ts = tts.ExecuteReaderTable(sqlCmd, out _table);
            scorecardItems = _table;
            return ts;
        }

        public void UpdatePerfmonMachinesList(string sqlConn, int connTimeout, int cmdTimeout)
        {
            TalkToSql tts = new TalkToSql(sqlConn, connTimeout, cmdTimeout);
            string sqlCmd = String.Format(TSL_ReportingEngine.Sql_GETPERFMONMACHINELIST, runId);
            perfmonMachines.Clear();
            perfmonMachines = tts.ExecuteReaderStringCollection(sqlCmd);
        }

        public string UpdateMainReportStringWithValues(string inputString, string startDelimiter = "{{", string endDelimiter = "}}")
        {
            Dictionary<string, string> tmp = new Dictionary<string, string>();
            return UpdateMainReportStringWithValues(inputString, tmp, startDelimiter, endDelimiter);
        }

        public string UpdateMainReportStringWithValues(string inputString, Dictionary<string, string> timingInfo, string startDelimiter = "{{", string endDelimiter = "}}")
        {
            StringBuilder sb = new StringBuilder(inputString);
            sb = sb.Replace(startDelimiter + "LoadTestName" + endDelimiter, LoadTestName);
            sb = sb.Replace(startDelimiter + "LoadTestExecutionDate" + endDelimiter, startTime.ToString("dddd, MMMM dd yyyy h:mm:ss tt"));
            sb = sb.Replace(startDelimiter + "StartTimeFormatted" + endDelimiter, startTime.ToString());
            sb = sb.Replace(startDelimiter + "DurationFormatted" + endDelimiter, (duration / 60).ToString() + " minutes");
            sb = sb.Replace(startDelimiter + "Outcome" + endDelimiter, outcome);

            sb = sb.Replace(startDelimiter + "RunSettings" + endDelimiter, runSettingsUsed);
            //sb = sb.Replace(startDelimiter + "MaxUsers" + endDelimiter, "");
            sb = sb.Replace(startDelimiter + "Controller" + endDelimiter, controllerName);
            sb = sb.Replace(startDelimiter + "AgentCount" + endDelimiter, agents.Count.ToString());
            sb = sb.Replace(startDelimiter + "TestDescription" + endDelimiter, description);

            if (timingInfo != null)
            {
                foreach (KeyValuePair<string, string> kvp in timingInfo)
                {
                    sb = sb.Replace(startDelimiter + kvp.Key + endDelimiter, kvp.Value);
                }
            }
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");
            //sb = sb.Replace(startDelimiter + "" + endDelimiter, "");

            return sb.ToString();
        }

        public static string StripUserNameFromAnalysisNotes(string inputString, string startDelimiter = "[", string endDelimiter = "]")
        {
            int x = inputString.IndexOf(startDelimiter);
            int y = inputString.IndexOf(endDelimiter);
            if (x == 0
                && y > x
                && inputString.Length > y + 1)
            {
                return inputString.Substring(y + 1);
            }
            else
                return "";
        }
        #endregion
    }

    public class ScoreCardItem
    {
        /*<ScoreCardItem 
         * Name="LoadTestRunId" 
         * DataType="int" 
         * UseInReport="True" 
         * ShowGraph="false" 
         * ShowGoal="false" 
         * Goal="1" 
         * HigherIsBetter="true" 
         * YAxisMax="" 
         * Title="Load Test Run Id" 
         * Description="The run ID of the test"></ScoreCardItem> */

        public string Name { get; set; }
        public string DataType { get; set; }
        public bool UseInReport { get; set; }
        public bool ShowGraph { get; set; }
        public bool ShowGoal { get; set; }
        public double Goal { get; set; }
        public bool HigherIsBetter { get; set; }
        public int YAxisMax { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
    }

    [Flags]
    public enum ResultTypesStoredInLoadTest
    {
        ContainsPages = 1,
        ContainsTransactions = 2,
        ContainsDetailedTimingInfo = 4,
        IsLocalRun = 8,
        ContainsAnalysisNotes = 16,
        TestAborted = 32,
        LoadTestParsingFailed = 64,
        ContainsStepLoad = 128
    };

}
